package com.dong.c05_nio_group_chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * <h1></h1>
 *
 * @author : dzj
 * @create: 2020-03-18 17:15
 */

public class GroupChatServer {
    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    private static final String HOST="localhost";
    private static final int PORT= 6667;

    public GroupChatServer() {
        try {
            this.selector = Selector.open();
            this.serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(HOST,PORT));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //监听
    public void listen() {
        try {
            //循环处理
            while(true) {
                int count = selector.select(2000);
                if(count==0) {
                    System.out.println("间隔2秒, 没有客户端进行连接");
                }else {
                    //有连接
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = iterator.next();
                        if(selectionKey.isAcceptable()) {
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector,SelectionKey.OP_READ);
                            System.out.println(socketChannel.getRemoteAddress()+ "上线了");
                        }else if(selectionKey.isReadable()) {
                            //专门处理
                            readData(selectionKey);

                        }
                        //移除, 防止重复处理
                        iterator.remove();
                    }
                }
            }
        } catch (IOException e) {

            e.printStackTrace();
        } finally {

        }
    }
    //服务器接收客户端消息, 并实现转发, 不转发到自己
    private void readData(SelectionKey selectionKey) {
        SocketChannel channel =null;
        SocketAddress remoteAddress = null;
        try {
            remoteAddress = channel.getRemoteAddress();
             channel = (SocketChannel) selectionKey.channel();
             ByteBuffer buffer = ByteBuffer.allocate(1024);
            int len = channel.read(buffer);
            if(len>0) {
                String msg = new String(buffer.array());
                System.out.println(remoteAddress +"发送消息: "+ msg);
                //转发消息
                sendInfoToOthers(msg,channel);
            }


        } catch (IOException e) {
            try {
                System.out.println(remoteAddress +"离线了");
                //取消注册
                selectionKey.cancel();
                //关闭通道
                channel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
    }
    //转发消息
    private void sendInfoToOthers(String msg,SocketChannel senderChannel) {
        try {
            System.out.println("服务端进行消息转发: "+msg);
            Iterator<SelectionKey> iterator = selector.keys().iterator();
            ByteBuffer sendBuffer = ByteBuffer.wrap(msg.getBytes());
            while(iterator.hasNext()) {
                //转发信息
                SelectionKey currentKey = iterator.next();
                if(currentKey.channel() instanceof  SocketChannel) {
                    SocketChannel targetChannel = (SocketChannel) currentKey.channel();
                    if(targetChannel.equals(senderChannel)) {
                        System.out.println("发现了一个SockerChannel 是发送方"+senderChannel.hashCode());
                        continue;
                    }else {
                        System.out.println("发现了一个SockerChannel 是接收方"+senderChannel.hashCode());
                        targetChannel.write(sendBuffer);
                    }
                }else {
                    System.out.println("发现了一个ServerSockerChannel : "+senderChannel.hashCode());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        GroupChatServer server = new GroupChatServer();
        server.listen();
    }
}
